package com.share.common.httpclient.util;

import com.share.common.tools.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.springframework.util.StringUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.CertificateException;
import javax.validation.constraints.NotNull;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/*
 * 利用HttpClient进行post请求的工具类
 */
public class HttpsClientUtil {
    private static final Logger logger = Logger.getLogger(HttpsClientUtil.class);


    private HttpsClientUtil() {
    }


    /**
     * 真正使用的方法
     *
     * @param url     请求地址
     * @param timeOut 超时连接
     * @return html
     */
    public static String getRequest(String url, int timeOut) {
        String result = "";
        try {
            URL u = new URL(url);
            if ("https".equalsIgnoreCase(u.getProtocol())) {
                SslUtils.ignoreSsl();
            }
            URLConnection conn = u.openConnection();
            conn.setConnectTimeout(timeOut);
            conn.setReadTimeout(timeOut);
            result = IOUtils.getString(conn.getInputStream());
            logger.debug("查询出的返回的结果集合为" + result);
        } catch (Exception e) {
            logger.error("访问远程访问数据出错!!!");
            logger.error("错误信息为" + e.getMessage());
            logger.error(e.getStackTrace());
            e.printStackTrace();
        }
        return result;
    }

    public static String doGet(@NotNull String url, Map<String, String> parms) {
        String urlAndParms = null;
        try {
            StringBuffer sbUrl = new StringBuffer(url);
            sbUrl.append("?");
            for (String key : parms.keySet()) {
                sbUrl.append(key + "=" + parms.get(key).trim() + "&");
            }
            urlAndParms = sbUrl.subSequence(0, sbUrl.length() - "&".length()).toString();
            if (logger.isDebugEnabled()) {
                logger.debug("查询的url地址为" + urlAndParms);
                logger.debug("发送的参数为" + parms);
            }
        } catch (Exception e) {
            logger.error("对字符编码的时候出错");
            logger.error("发送请求的时候的url地址为" + url);
            logger.error("发送请求的方式为GET");
            logger.error("发送请求的参数为" + parms);
            logger.error(e.getLocalizedMessage());
            logger.error(e.getStackTrace());
            logger.error("发生异常的数据为" + e);

        }
        return getRequest(urlAndParms, 1000);
    }

    public static String doGetIPhone(@NotNull String url, Map<String, String> parms) {
        String urlAndParms = null;
        try {
            StringBuffer sbUrl = new StringBuffer(url);
            sbUrl.append("?");
            for (String key : parms.keySet()) {
                sbUrl.append(key + "=" + parms.get(key).trim() + "&");
            }
            urlAndParms = sbUrl.subSequence(0, sbUrl.length() - "&".length()).toString();

        } catch (Exception e) {


        }
        return doGetIPhone(urlAndParms, null, "UTF-8");
    }

    public static String doGet(@NotNull String url) {
        String msg = "未知 发送请求失败!";
        try {
            msg = send(url, null, "UTF-8");
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return msg;
    }


    public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sc = SSLContext.getInstance("SSLv3");

        // 实现一个X509TrustManager接口，用于绕过验证，不用修改里面的方法
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sc.init(null, new TrustManager[]{trustManager}, null);
        return sc;
    }

    public static String send(String url, Map<String, String> map, String encoding) throws KeyManagementException, NoSuchAlgorithmException, IOException {
        String body = "";
        //采用绕过验证的方式处理https请求
        SSLContext sslcontext = createIgnoreVerifySSL();

        // 设置协议http和https对应的处理socket链接工厂的对象
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(sslcontext))
                .build();
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        HttpClients.custom().setConnectionManager(connManager);

        //创建自定义的httpclient对象
        CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();
        //CloseableHttpClient client = HttpClients.createDefault();

        //创建post方式请求对象
        HttpPost httpPost = new HttpPost(url);

        //装填参数
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        if (map != null) {
            for (Entry<String, String> entry : map.entrySet()) {
                nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }
        //设置参数到请求对象中
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding));

        logger.info("请求地址：" + url);
        logger.info("请求参数：" + nvps.toString());

        //设置header信息
        //指定报文头【Content-type】、【User-Agent】
        httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
        httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

        //执行请求操作，并拿到结果（同步阻塞）
        CloseableHttpResponse response = client.execute(httpPost);
        //获取结果实体
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            //按指定编码转换结果实体为String类型
            body = EntityUtils.toString(entity, encoding);
        }
        EntityUtils.consume(entity);
        //释放链接
        response.close();
        return body;
    }

    /**
     * 模拟手机发送GET请求
     * 说白了 就是专门为百度的请求dan君方式发送的请求
     *
     * @param url 发送地址
     * @param map 封装参数
     * @return html
     */
    public static String doGetIPhone(String url, Map<String, String> map, String encoding) {
        String body = "";
        if (StringUtils.isEmpty(encoding)) {
            encoding = "UTF-8";
            logger.warn("没有指定编码方式,默认使用utf-8");
        }
        try {
            //采用绕过验证的方式处理https请求
            SSLContext sslcontext = createIgnoreVerifySSL();

            // 设置协议http和https对应的处理socket链接工厂的对象
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", new SSLConnectionSocketFactory(sslcontext))
                    .build();
            PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            HttpClients.custom().setConnectionManager(connManager);

            //创建自定义的httpclient对象
            CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();
            //CloseableHttpClient client = HttpClients.createDefault();

            //创建post方式请求对象
            HttpPost httpPost = new HttpPost(url);

            //装填参数
            List<NameValuePair> nvps = new ArrayList<NameValuePair>();
            if (map != null) {
                for (Entry<String, String> entry : map.entrySet()) {
                    nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
            }
            //设置参数到请求对象中
            httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding));

            logger.info("请求地址：" + url);
            logger.info("请求参数：" + nvps.toString());

            //设置header信息
            //指定报文头【Content-type】、【User-Agent】
            httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
            httpPost.setHeader("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_2_1 like Mac OS X) AppleWebKit/602.4.6 (KHTML, like Gecko) Mobile/14D27 SearchCraft/1.12.2 (Baidu; P2 10.2.1)");
            httpPost.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
            httpPost.setHeader("Referer", "https://secr.baidu.com/entry?status=1-1-1-1-1-1&version=7");
            httpPost.setHeader("BAIDULOC", "12959494.780000_4810265.810000_1000_131_1516553614.118702");
            httpPost.setHeader("BAIDUID", "3DF5C687838F53C1B689B7724C8937CE:FG=1");

            //执行请求操作，并拿到结果（同步阻塞）
            CloseableHttpResponse response = client.execute(httpPost);
            //获取结果实体
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                //按指定编码转换结果实体为String类型
                body = EntityUtils.toString(entity, encoding);
            }
            EntityUtils.consume(entity);
            //释放链接
            response.close();
        } catch (Exception e) {
            logger.error(e.getStackTrace());
            logger.error(e.getMessage());
        }

        return body;

    }


}
